public class ValidateAddresses {
    public static Boolean AsyncValidationFlag = false;
    
    @Future(callout=true) 
    public static void validateAddressSOAP(Set<ID> ids) {
        try {
            // 検証対象となる住所リストの作成
            Map<ID, Candidate__c> mapCands = findCandidates(ids);
            List<ValidateAddressesSOAP.addressSOAP> listAddress = new List<ValidateAddressesSOAP.addressSOAP>();
            for (Candidate__c cand : mapCands.values()) {
                ValidateAddressesSOAP.addressSOAP address = new ValidateAddressesSOAP.addressSOAP();
                address.id = cand.id;
                address.line1 = cand.Street_Address_1__c;
                address.line2 = cand.Street_Address_2__c;
                address.city = cand.city__c;
                address.state = cand.state_Province__c;
                address.country = cand.country__c;
                address.zipCode = cand.zip_postal_code__c;
                listAddress.add(address);
            }
                        
            // コールアウト実行
            ValidateAddressesSOAP.ValidateAddressesPort port = new ValidateAddressesSOAP.ValidateAddressesPort();
            List<ValidateAddressesSOAP.validationResultSOAP> listResult = port.ValidateAddresses(listAddress);

            // コールアウト結果の検証
            for (ValidateAddressesSOAP.validationResultSOAP result : listResult) {
                Candidate__c cand = mapCands.get(result.testAddress.id);
                if (result.isValid) {
                    cand.Valid_Address__c = true;
                    cand.Address_Error__c = null;
                } else {
                    cand.Valid_Address__c = false;
                    cand.Address_Error__c = '住所不正';                 
                }
            }
            
            // Candidateの更新
            AsyncValidationFlag = true;
            update mapCands.values();
        } catch (Exception ex) {
            // 例外処理
            System.debug('ERROR: '+ ex);
            Error_Log__c log = new Error_Log__c();
            log.trace__c = ex.getCause() + '\n' + ex.getMessage();
            insert log;        
        }
    }

	//TODO: @futureアノテーションを使用してこのメソッドがWebサービスコールアウトであることを指定
    @Future(callout=true) 
    public static void validateAddressREST(Set<ID> ids) {
        try {
            // 検証対象となる住所リストの作成
            Map<ID, Candidate__c> mapCands = findCandidates(ids);
            List<ValidateAddressesREST.Address> listAddress = new List<ValidateAddressesREST.Address>();
            for (Candidate__c cand : mapCands.values()) {
                ValidateAddressesREST.Address address = new ValidateAddressesREST.Address();
                address.id = cand.id;
                address.line1 = cand.Street_Address_1__c;
                address.line2 = cand.Street_Address_2__c;
                address.city = cand.city__c;
                address.state = cand.state_Province__c;
                address.country = cand.country__c;
                address.zipCode = cand.zip_postal_code__c;
                listAddress.add(address);
            }
                        
            // コールアウト実行
			//TODO: ValidateAddressesREST型の変数portを作成し、デフォルトコンストラクタで作成したインスタンスを代入する
            ValidateAddressesREST port = new ValidateAddressesREST();
			//TODO: portのValidateAddressesメソッドを呼び出しlistAddressを与える。実行結果は変数listResultに代入する 
			//NOTE: Review the class definition of ValidateAddressesREST to fine the return type of the ValidateAddresses()
            List<ValidateAddressesREST.Result> listResult = port.ValidateAddresses(listAddress);

            // 実行結果の検証
            for (ValidateAddressesREST.Result result : listResult) {
                Candidate__c cand = mapCands.get(result.testAddress.id);
                if (result.isValid) {
                    cand.Valid_Address__c = true;
                    cand.Address_Error__c = null;
                } else {
                    cand.Valid_Address__c = false;
                    cand.Address_Error__c = '住所不正';
                }
            }
            
            // Candidateの更新
            AsyncValidationFlag = true;
            update mapCands.values();
        } catch (Exception ex) {
            // 例外処理
            System.debug('ERROR: '+ ex);
            Error_Log__c log = new Error_Log__c();
            log.trace__c = ex.getCause() + '\n' + ex.getMessage();
            insert log;        
        }
    }
    
    private static Map<ID, Candidate__c> findCandidates(Set<ID> ids) {
        Map<ID, Candidate__c> output;
        output = new Map<ID, Candidate__c>([SELECT ID, Street_Address_1__c, Street_Address_2__c, city__c,
                                                state_Province__c, country__c, zip_postal_code__c
                                            FROM candidate__c
                                            WHERE id in :ids]);
        return output;
    }
}